﻿/* * * * * * * * * * * * * * * *
 * SDL ToolBox                 *
 * Copyright (c) VosSoft 2009  *
 * * * * * * * * * * * * * * * *
 * file:    class config       *
 * date:    2009-05-05         *
 * * * * * * * * * * * * * * * */

using System.Collections.Generic;
using System.IO;
using System.Xml;

namespace SDL_ToolBox
{
    /// <summary>
    /// Verwaltet eine Einstellung
    /// </summary>
    public class Setting
    {
        private string name;
        private string value;
        private string defaultValue;
        private bool wasInFile;

        /// <summary>
        /// Der Name der Einstellung
        /// </summary>
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        /// <summary>
        /// Der Wert der Einstellung
        /// </summary>
        public string Value
        {
            get
            {
                if (this.value != null)
                    return this.value;
                else
                    return this.defaultValue;
            }
            set { this.value = value; }
        }

        /// <summary>
        /// Der Defaultwert für das Lesen
        /// </summary>
        public string DefaultValue
        {
            get { return defaultValue; }
            set { defaultValue = value; }
        }

        /// <summary>
        /// Gibt an, ob die Einstellung
        /// in der Datei gefunden wurde
        /// </summary>
        public bool WasInFile
        {
            get { return wasInFile; }
            set { wasInFile = value; }
        }

        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="name">Der Name der Einstellung</param>
        /// <param name="defaultValue">Der Defaultwert für das Lesen</param>
        public Setting(string name, string defaultValue)
        {
            this.name = name;
            this.defaultValue = defaultValue;
        }
    }

    /// <summary>
    /// Auflistung zum Speichern mehrerer Einstellungen
    /// </summary>
    public class Settings : Dictionary<string, Setting>
    {
        /// <summary>
        /// Fügt der Auflistung eine neue Einstellung hinzu
        /// </summary>
        /// <param name="settingName">Der Name der Einstellung</param>
        /// <param name="defaultValue">Der Defaultwert für das Lesen</param>
        public void Add(string settingName, string defaultValue)
        {
            this.Add(settingName,
               new Setting(settingName, defaultValue));
        }
    }

    /// <summary>
    /// Verwaltet eine Einstellungs-Sektion
    /// </summary>
    public class Section
    {
        private string name;
        private Settings settings;

        /// <summary>
        /// Der Name der Sektion
        /// </summary>
        public string Name
        {
            get { return name; }
            set { name = value; }
        }

        /// <summary>
        /// Die Einstellungen der Sektion
        /// </summary>
        public Settings Settings
        {
            get { return settings; }
            set { settings = value; }
        }

        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="sectionName">Der Name der Sektion</param>
        public Section(string sectionName)
        {
            this.name = sectionName;
            this.settings = new Settings();
        }
    }

    /// <summary>
    /// Auflistung zur Speicherung von Sektionen
    /// </summary>
    public class Sections : Dictionary<string, Section>
    {
        /// <summary>
        /// Fügt der Auflistung ein neues Section-Objekt hinzu
        /// </summary>
        /// <param name="name">Der Name der Sektion</param>
        public void Add(string name)
        {
            this.Add(name, new Section(name));
        }
    }

    /// <summary>
    /// Klasse zur Verwaltung von Konfigurationsdaten
    /// </summary>
    public class Config
    {
        /// <summary>
        /// Speichert den Dateinamen der XML-Datei
        /// </summary>
        private string fileName;
        private Sections sections;

        /// <summary>
        /// Verwaltet die Sektionen
        /// </summary>
        public Sections Sections
        {
            get { return sections; }
            set { sections = value; }
        }

        /// <summary>
        /// Konstruktor
        /// </summary>
        /// <param name="fileName">Der Dateiname der XML-Datei</param>
        public Config(string fileName)
        {
            this.fileName = fileName;
            this.sections = new Sections();
        }

        /// <summary>
        /// Erstellt eine neue Konfigurationsdatei
        /// </summary>
        /// <param name="path">Pfad zum Speicherort der Ressourcen</param>
        /// <returns>Gibt true zurück wenn das Erstellen erfolgreich war</returns>
        public bool Create(string path)
        {
            // Hauptfenster
            sections.Add("frmMain");
            sections["frmMain"].Settings.Add("left", "64");
            sections["frmMain"].Settings.Add("top", "64");
            sections["frmMain"].Settings.Add("width", "900");
            sections["frmMain"].Settings.Add("height", "600");
            sections["frmMain"].Settings.Add("windowState", "Normal");
            // Einstellungsfenster
            sections.Add("frmEinstellungen");
            sections["frmEinstellungen"].Settings.Add("left", "64");
            sections["frmEinstellungen"].Settings.Add("top", "64");
            // Map
            sections.Add("map");
            sections["map"].Settings.Add("path", Path.Combine(path, "maps"));
            sections["map"].Settings.Add("x", "40");
            sections["map"].Settings.Add("y", "30");
            sections["map"].Settings.Add("size", "16");
            sections["map"].Settings.Add("background", "back.png");
            sections["map"].Settings.Add("foreground", "fore.png");
            // Raster
            sections.Add("grid");
            sections["grid"].Settings.Add("color", "-16777216");
            sections["grid"].Settings.Add("alpha", "96");
            sections["grid"].Settings.Add("style", "Strich-Punkt-Punkt");
            sections["grid"].Settings.Add("width", "1");
            // Auswahl
            sections.Add("selection");
            sections["selection"].Settings.Add("color", "-16777216");
            sections["selection"].Settings.Add("alpha", "128");
            sections["selection"].Settings.Add("style", "Durchgezogen");
            sections["selection"].Settings.Add("width", "2");
            // Ressourcen
            sections.Add("resources");
            sections["resources"].Settings.Add("path", Path.Combine(path, "resources"));
            // Texturen
            sections.Add("textures");
            sections["textures"].Settings.Add("path", Path.Combine(path, "textures"));

            Save();
            return true;
        }

        /// <summary>
        /// Ließ die Konfigurationsdaten
        /// </summary>
        /// <param name="loadAll">die gesamte XML-Datei einlesen</param>
        /// <returns>Gibt true zurück wenn das Lesen erfolgreich war</returns>
        public bool Load(bool loadAll)
        {
            // Variable für den Rückgabewert
            bool returnValue = true;

            // XmlDocument-Objekt für die Einstellungs-Datei erzeugen
            XmlDocument xmlDoc = new XmlDocument();

            // Datei laden
            try
            {
                xmlDoc.Load(this.fileName);
            }
            catch (IOException ex)
            {
                throw new IOException("Fehler beim Laden der Konfigurationsdatei '" +
                   this.fileName + "': " + ex.Message);
            }
            catch (XmlException ex)
            {
                throw new XmlException("Fehler beim Laden der Konfigurationsdatei '" +
                   this.fileName + "': " + ex.Message, ex);
            }

            if (loadAll == true)
            {
                sections.Clear();
                foreach (XmlNode nodeSection in xmlDoc.ChildNodes[1])
                {
                    sections.Add(nodeSection.Name);
                    foreach (XmlNode nodeSetting in nodeSection.ChildNodes)
                    {
                        sections[nodeSection.Name].Settings.Add(nodeSetting.Name, nodeSetting.InnerText);
                    }
                }
            }
            else
            {
                // Alle Sektionen durchgehen und die Einstellungen einlesen
                foreach (Section section in this.sections.Values)
                {
                    // Alle Einstellungen der Sektion durchlaufen
                    foreach (Setting setting in section.Settings.Values)
                    {
                        // Einstellung im XML-Dokument lokalisieren
                        XmlNode settingNode = xmlDoc.SelectSingleNode(
                           "/config/" + section.Name + "/" + setting.Name);
                        if (settingNode != null)
                        {
                            // Einstellung gefunden
                            setting.Value = settingNode.InnerText;
                            setting.WasInFile = true;
                        }
                        else
                        {
                            // Einstellung nicht gefunden
                            setting.Value = setting.DefaultValue;
                            setting.WasInFile = false;
                            returnValue = false;
                        }
                    }
                }
            }

            // Ergebnis zurückmelden
            return returnValue;
        }

        /// <summary>
        /// Speichert die Konfigurationsdaten
        /// </summary>
        public void Save()
        {
            // XmlDocument-Objekt für die Einstellungs-Datei erzeugen
            XmlDocument xmlDoc = new XmlDocument();

            // Skelett der XML-Datei erzeugen
            xmlDoc.LoadXml("<?xml version=\"1.0\" encoding=\"utf-8\" " +
               "standalone=\"yes\"?><config></config>");

            // Alle Sektionen durchgehen und die Einstellungen schreiben
            foreach (Section section in this.sections.Values)
            {
                // Element für die Sektion erzeugen und anfügen
                XmlElement sectionElement = xmlDoc.CreateElement(section.Name);
                xmlDoc.DocumentElement.AppendChild(sectionElement);

                // Alle Einstellungen der Sektion durchlaufen
                foreach (Setting setting in section.Settings.Values)
                {
                    // Einstellungs-Element erzeugen und anfügen
                    XmlElement settingElement =
                       xmlDoc.CreateElement(setting.Name);
                    settingElement.InnerText = setting.Value;
                    sectionElement.AppendChild(settingElement);
                }
            }

            // Datei speichern
            try
            {
                xmlDoc.Save(this.fileName);
            }
            catch (IOException ex)
            {
                throw new IOException("Fehler beim Speichern der " +
                   "Konfigurationsdatei '" + this.fileName + "': " + ex.Message);
            }
            catch (XmlException ex)
            {
                throw new XmlException("Fehler beim Speichern der " +
                   " Konfigurationsdatei '" + this.fileName + "': " +
                   ex.Message, ex);
            }
        }
    }
}
